<?php
/**
 * 
 * Meshtile API common library
 * @author tuanlq@lifetimetech.vn
 */

App::uses('Template', 'Lib/Meshtiles');
App::uses('HttpSocket', 'Network/Http');

class MeshtilesApi {
	
	/*
	 * Pre-defined Meshtiles API Template
	 * required: /app/Lib/Meshtiles/Tempate.php
	 */
	private $_Template = null;
	
	/*
	 * HttpSocket. Which can be used for making requests.
	 * required: /lib/Cake/Network/Http/HttpSocket.php
	 */
	private $_HttpSocket = null;
	
	/**
	 * Constructor method
	 */
	public function __construct() {
		$this->_Template = new Template();
		$this->_HttpSocket = new HttpSocket();
	}
	
	/**
	 * For static calling.
	 * So we can make the static calling like this:
	 * Meshtiels::instance()->callApi() 
	 */
	public static function instance() {
		return new MeshtilesApi();
	}
	
	public function __call($name, $arguments) {
		$res = $this->callAPI($name, $arguments[0], $logging);
		
		return $res === false ? $logging : $res;
	}
	
	/**
	 * 
	 * Main function which parse params and call meshtile API
	 * 
	 * @param	string	$method		the API method 's name
	 * @param	array	$args		arguments
	 * @param	array	$logging	contain logging information
	 * 
	 * @return	json-decoded array of api response / 
	 * 			false if have something wrong
	 * 
	 * @author	tuanlq@lifetimetech.vn
	 */
	public function callAPI($method = null, array $args = array(), &$logging = array()) {
		/*
		 * INIT
		 * ----
		 */
		if (!method_exists($this, 'callAPI')) {
			return false;
		}

		/*
		 * Recheck input params
		 * --------------------
		 */
		if (!is_string($method) || !is_array($args)) {
			$logging['ERROR'] = 'Invalid input parameters';
			
			return false;
		}
		
		if (!isset($this->_Template->{$method})) {
			$logging['ERROR'] = 'The API methods is not existed';
			
			return false;
		}
		
		$apiMethod = $this->_Template->{$method};
		
		// Required args of API methods, but not  present at input $args params
		$args = array_merge($args, $this->_Template->appConfig);
		$requiredArgs = array_diff($apiMethod['args'], array_keys($args));
		if (!empty($requiredArgs)) {
			$logging['ERROR'] = implode(', ', $requiredArgs) . ' is required';
			
			return false;
		}
		
		/*
		 * Proccesing API request
		 * ----------------------
		 */
		
		$Url = API_SERVER;
		$Url .= $this->_Template->apiGroup[$apiMethod['group']];
		$Url .= $apiMethod['method'];
		
		$response = $this->_HttpSocket->get($Url, $args);
		
		$body = json_decode($response->body, true);
		
// 		if (isset($body['message']) && $body['message'] == 'API-ERR-EXPIRED') {
// 			$refresh = $this->refreshAccessToken();
			
// 			if ($refresh) {
// 				$args['access_token'] = $refresh['access_token'];
				
// 				$response = $this->_HttpSocket->get($Url, $args);
				
// 				$body = json_decode($response->body, true);
// 			}
// 		}
		
		$logging['URL'] = $Url;
		$logging['ARGS'] = $args;
		$logging['RESPONSE'] = $response;
		
		/*
		 * if result is false or null, i want to return empty array.
		 * The false result is meaning have something error
		 */ 
		return $body ? $body : array();
	}
	
	public function refreshAccessToken() {
		if (!AuthComponent::user('credentials.refresh_token')) {
			return false;
		}
		
		$Url = API_SERVER . '/oauth/refreshtoken';
		$args = array_merge(
			Configure::read('Meshtiles.config'),
			array('refresh_token' => AuthComponent::user('credentials.refresh_token'))
		);
		
		$refresh = $this->_HttpSocket->get($Url, $args);
		
		$refresh = json_decode($refresh->body, true);
		
		if (!$refresh) {
			return false;
		}
		
		CakeSession::write('Auth.User.credentials.access_token', $refresh['access_token']);
		
		unset($refresh['is_success']);
		
		return $refresh;
	}
}